import { Component, OnInit } from '@angular/core';
import { ListService, LocalizationService } from '@abp/ng.core';
import { SelectionModel } from '@angular/cdk/collections';
import { NzTreeFlatDataSource, NzTreeFlattener } from 'ng-zorro-antd/tree-view';
import { FlatTreeControl } from '@angular/cdk/tree';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { EditState } from 'joy-abpui-angular';
import { EntityTreeNode, EntityFlatNode } from "../../core/basic-tree-node";
import { NzContextMenuService, NzDropdownMenuComponent } from 'ng-zorro-antd/dropdown';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzMessageService } from 'ng-zorro-antd/message';
import { ItemCategoryDto, ItemCategoryService } from '../../proxy/joy/erp/basic-archives/item-masters';
import { ItemCategoryRefEntityService } from '../item-category-ref-entity/item-category-ref-entity.service';
import { debounce } from '../../core/debounce.util';

@Component({
  selector: 'lib-item-category-detail',
  templateUrl: './item-category-detail.component.html',
  styleUrls: ['./item-category-detail.component.less'],
  providers: [ListService],
})
export class ItemCategoryDetailComponent implements OnInit {
  entityConfig = {
    defaultValue: {},
  };
  editState: EditState;
  validateForm: FormGroup;
  currentEntity: ItemCategoryDto;

  // 以下为树结构相关属性
  flatNodeMap: Map<EntityFlatNode<ItemCategoryDto>, EntityTreeNode<ItemCategoryDto>>;
  nestedNodeMap: Map<EntityTreeNode<ItemCategoryDto>, EntityFlatNode<ItemCategoryDto>>;
  selectListSelection: SelectionModel<EntityFlatNode<ItemCategoryDto>>;
  treeControl: FlatTreeControl<EntityFlatNode<ItemCategoryDto>>;
  treeFlattener: NzTreeFlattener<EntityTreeNode<ItemCategoryDto>, EntityFlatNode<ItemCategoryDto>, EntityFlatNode<ItemCategoryDto>>;
  dataSource: NzTreeFlatDataSource<EntityTreeNode<ItemCategoryDto>, EntityFlatNode<ItemCategoryDto>, EntityFlatNode<ItemCategoryDto>>;
  treeData: EntityTreeNode<ItemCategoryDto>[] = [];
  currentNode: EntityFlatNode<ItemCategoryDto>;
  transformer = (node: EntityTreeNode<ItemCategoryDto>, level: number): EntityFlatNode<ItemCategoryDto> => {
    const existingNode = this.nestedNodeMap.get(node);
    const flatNode =
      existingNode && existingNode.key === node.key
        ? existingNode
        : {
            ...node,
            name: node.name,
            key: node.key,
            level,
            expandable: !!node.children?.length,
            disabled: !!node.disabled,
          };
    flatNode.name = node.name;
    this.flatNodeMap.set(flatNode, node);
    this.nestedNodeMap.set(node, flatNode);
    return flatNode;
  };
  hasChild = (_: number, node: EntityFlatNode<ItemCategoryDto>): boolean => node.expandable;
  trackBy = (_: number, node: EntityFlatNode<ItemCategoryDto>): string =>
    `${node.key}-${node.name}-${node.expandable}`;
  // 以上为树结构相关属性

  constructor(
    public fb: FormBuilder,
    public nzContextMenuService: NzContextMenuService,
    public localizationService: LocalizationService,
    public entityService: ItemCategoryService,
    public refEntityService: ItemCategoryRefEntityService,
    public modal: NzModalService,    
    public message: NzMessageService,
  ) {
    // 以下为树结构相关属性初始化
    this.flatNodeMap = new Map<EntityFlatNode<ItemCategoryDto>, EntityTreeNode<ItemCategoryDto>>();
    this.nestedNodeMap = new Map<EntityTreeNode<ItemCategoryDto>, EntityFlatNode<ItemCategoryDto>>();
    this.selectListSelection = new SelectionModel<EntityFlatNode<ItemCategoryDto>>(false);
    this.treeControl = new FlatTreeControl<EntityFlatNode<ItemCategoryDto>>(
      node => node.level,
      node => node.expandable
    );
    this.treeFlattener = new NzTreeFlattener(
      this.transformer,
      node => node.level,
      node => node.expandable,
      node => node.children
    );
    // 以上为树结构相关属性初始化

    this.editState = EditState.Empty;
    this.dataSource = new NzTreeFlatDataSource(this.treeControl, this.treeFlattener);
  }
  
  ngOnInit(): void {
    this.editState = EditState.Empty;
    this.currentEntity = this.entityConfig.defaultValue as ItemCategoryDto;
    this.validateForm = this.fb.group({
      displayName: [this.entityConfig.defaultValue['displayName'], [Validators.required, Validators.maxLength(200)]],
    });

    this.validateForm.valueChanges.subscribe(_ => {
      if (this.editState == EditState.Empty) {
        this.editState = EditState.Creating;
      } else if (this.editState == EditState.View) {
        this.editState = EditState.Editing;
      }
    });

    this.entityService.getChildren(null, true)    
      .subscribe(result => {
        this.treeData = this.createEntityTreeNodes(result.items, null);
        this.dataSource.setData(this.treeData);
      });
  }
  
  createEntityTreeNodes(
    list: ItemCategoryDto[],
    parent: ItemCategoryDto,
    parentIdPropretyName?: string,
    idPropertyName?: string
  ): EntityTreeNode<ItemCategoryDto>[] {
    let treeNodes: EntityTreeNode<ItemCategoryDto>[] = [];
    let parentIdKey = !parentIdPropretyName ? 'parentId' : parentIdPropretyName;
    let idKey = !idPropertyName ? 'id' : idPropertyName;
    let parentId = !parent ? null : parent[idKey];
    for (let node of list.filter(x => x[parentIdKey] == parentId)) {
      const children = this.createEntityTreeNodes(list, node, parentIdKey, idKey);

      treeNodes = [
        ...treeNodes,
        {
          ...node,
          children,
          ...this.createEntityTreeNode(node),
        },
      ];
    }
    return treeNodes;
  }

  createEntityTreeNode(model: ItemCategoryDto): EntityTreeNode<ItemCategoryDto> {
    return {
      ...model,
      key: model.id,
      name: model.displayName, //TODO:将类的displayName字段设置为树结构中显示的名称
    };
  }

  toggleExpand(node: EntityFlatNode<ItemCategoryDto>) {
    if (this.treeControl.isExpanded(node)) {
      this.treeControl.collapse(node);
    } else {
      this.treeControl.expand(node);
    }
  }

  contextMenu($event: MouseEvent, menu: NzDropdownMenuComponent, node: EntityFlatNode<ItemCategoryDto>) {
    this.selectListSelection.select(node);
    this.nzContextMenuService.create($event, menu);
  }

  selectNode(node: EntityFlatNode<ItemCategoryDto>) {
    this.selectListSelection.select(node);
    this.setCurrentEntity(node);
  }

  get selectedNode(): EntityFlatNode<ItemCategoryDto> {
    return this.selectListSelection.selected[0];
  }

  @debounce()
  giveup() {
    this.giveUpConfirm().then(_ => {
      if (this.editState == EditState.Creating) {
        //表单状态为创建时，清空数据
        this.changeToEmpty();
      } else if (this.editState == EditState.Editing) {
        //表单状态为编辑时，恢复原数据
        this.setCurrentEntity(this.currentEntity);
      }
    });
  }

  @debounce()
  new() {
    this.checkDirty().then(_ => {
      this.changeToEmpty();
      this.refAddModal(null);
    });
  }

  @debounce()
  save() {
    this.entityService
        .update(this.currentEntity.id, {
          ...this.currentEntity,
          ...this.validateForm.value,
        })
        .subscribe(entity => {
          if (!!entity) {
            let treeNode = this.flatNodeMap.get(this.currentEntity as EntityFlatNode<ItemCategoryDto>);
            let resultTreeNode = this.createEntityTreeNode(entity);
            for (let key of Object.keys(resultTreeNode)) {
              if (key == 'level') continue;
              if (key == 'expandable') continue;

              treeNode[key] = resultTreeNode[key];
              this.currentEntity[key] = resultTreeNode[key];
            }
            this.dataSource.setData(this.treeData);
            this.setCurrentEntity(this.currentEntity);
            this.message.success(this.l('BasicArchives::UI:Message.EditSuccess'));
          }
        });
  }

  @debounce()
  delete() {    
    this.modal.confirm({
      nzTitle: this.l('BasicArchives::UI:Confirm.Title.Tips'),
      nzContent: this.l('BasicArchives::UI:Confirm.Content.DeleteConfirm'),
      nzOkText: this.l('BasicArchives::UI:Confirm.Button.OK'),
      nzCancelText: this.l('BasicArchives::UI:Confirm.Button.Cancel'),
      nzOnOk: () => {
        this.entityService.delete(this.currentEntity.id).subscribe(_ => {
          if (!!this.currentEntity['parentId']) {
            let parent = this.treeControl.dataNodes.find(x => x.id == this.currentEntity['parentId']);
            const parentNode = this.flatNodeMap.get(parent);
            parentNode.children = parentNode.children.filter(x => x.id != this.currentEntity.id);
            parent.expandable = !!parentNode.children.length;
          } else {
            this.treeData = this.treeData.filter(x => x.id != this.currentEntity.id);
          }
    
          this.dataSource.setData(this.treeData);
          this.changeToEmpty();
        });
      },
    });
  }

  @debounce()
  search(filter: string) {
    if(!!filter) {
      let node = this.treeControl.dataNodes.find(x => x.displayName == filter);
      if(!!node) {
        this.selectNode(node);
        this.expandParent(node);
      }
      else{
        this.message.warning(this.l('BasicArchives::UI:Message.CanNotFund', this.l('BasicArchives::Menu:BasicArchives.ArchivesManagement.ItemMasters.ItemCategory'), filter));
      }
    }
  }

  @debounce()
  refAddModal(parentId: string) {    
    this.refEntityService.show().subscribe(model => {
      if (!!model) {
        this.entityService
          .create({
            ...model,
            displayName: model.displayName,
            parentId,
          })
          .subscribe(result => {
            let node = this.treeControl.dataNodes.find(x => x.id == parentId);
            const parentNode = this.flatNodeMap.get(node);
            if (parentNode) {
              parentNode.children = parentNode.children || [];
              parentNode.children.push(this.createEntityTreeNode(result));
              node.expandable = true;
            } else {
              this.treeData.push(this.createEntityTreeNode(result));
            }
            this.dataSource.setData(this.treeData);
            this.treeControl.expand(node);
            this.selectNode(this.treeControl.dataNodes.find(x => x.id == result.id));
          });
      }
    });
  }

  protected changeToEmpty() {
    this.validateForm.reset(this.entityConfig.defaultValue, { emitEvent: false });
    this.selectListSelection.select(null);
    this.refreshFormValidationStatus();
    this.editState = EditState.Empty;
  }

  protected setCurrentEntity(entity: ItemCategoryDto) {
    this.currentEntity = entity;
    this.validateForm.reset(this.currentEntity, { emitEvent: false });
    this.refreshFormValidationStatus();
    this.editState = EditState.View;
  }

  protected giveUpConfirm(): Promise<any> {
    return new Promise((resolve, reject) => {
      if (this.editState != EditState.Creating && this.editState != EditState.Editing)
        return reject();
      this.modal.confirm({
        nzTitle: this.l('BasicArchives::UI:Confirm.Title.Tips'),
        nzContent: this.l('BasicArchives::UI:Confirm.Content.GiveUpConfirm'),
        nzOkText: this.l('BasicArchives::UI:Confirm.Button.OK'),
        nzCancelText: this.l('BasicArchives::UI:Confirm.Button.Cancel'),
        nzOnOk: () => resolve(null),
      });
    });
  }

  protected checkDirty(): Promise<any> {
    return new Promise(resolve => {
      if (this.editState == EditState.Creating || this.editState == EditState.Editing) {
        this.modal.confirm({
          nzTitle: this.l('BasicArchives::UI:Confirm.Title.Tips'),
          nzContent: this.l('BasicArchives::UI:Confirm.Content.ChangeStateConfirm'),
          nzOkText: this.l('BasicArchives::UI:Confirm.Button.OK'),
          nzCancelText: this.l('BasicArchives::UI:Confirm.Button.Cancel'),
          nzOnOk: () => resolve(null),
        });
      } else {
        resolve(null);
      }
    });
  }

  protected expandParent(node: EntityFlatNode<ItemCategoryDto>) {
    if(!!node.parentId) {
      let parent = this.treeControl.dataNodes.find(x => x.id == node.parentId);
      this.treeControl.expand(parent);

      this.expandParent(parent);
    }
  }
  
  protected l(key: string, ...parmas: string[]): string {
    return this.localizationService.instant(key, ...parmas);
  }  

  protected refreshFormValidationStatus() {
    Object.keys(this.validateForm.controls).forEach(key => {
      this.validateForm.controls[key].markAsPristine();
      this.validateForm.controls[key].updateValueAndValidity();
    });
  }

  public getSegmentTypeDisplayName(segmentType: string) {
    return this.localizationService.instant(`BasicArchives::UI:UniqueCodeSetting.SegmentType.${segmentType}`);
  }
}
